﻿// $Id: TypeMapping.cs 68 2008-05-09 16:11:33Z nvivo $

using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Xml;
using System.Xml.Schema;
using System.Xml.XPath;

namespace DBLGen.Plugins.Batch
{
    public class TypeMapping
    {
        private TypeMapping()
        { }

        private static XmlSchema _typeMappingSchema;

        private static XmlSchema TypeMappingSchema
        {
            get
            {
                if (_typeMappingSchema == null)
                    _typeMappingSchema = RM.LoadSchema("DBLGen.Schemas.TypeMapping.xsd");

                return _typeMappingSchema;
            }
        }

        private string _source;
        private string _target;
        private string _defaultCodeType;
        private string _customAttribute;

        private Dictionary<string, string> _maps = new Dictionary<string,string>();
        private Dictionary<string, string> _nullableMaps = new Dictionary<string,string>();

        public string Source
        {
            get
            {
                return _source;
            }
        }

        public string Target
        {
            get
            {
                return _target;
            }
        }

        public string DefaultCodeType
        {
            get
            {
                return _defaultCodeType ?? String.Empty;
            }
        }

        public string CustomAttribute
        {
            get
            {
                return _customAttribute;
            }
        }

        public string GetMappedType(string sqlType, bool useNullables)
        {
            string mappedType = null;

            if (useNullables)
                if (_nullableMaps.TryGetValue(sqlType, out mappedType))
                    return mappedType;

            if (_maps.TryGetValue(sqlType, out mappedType))
                return mappedType;

            return DefaultCodeType;
        }

        #region XML Loading

        public static TypeMapping LoadFromXml(string fileName)
        {
            XmlReaderSettings settings = new XmlReaderSettings();
            settings.ValidationType = ValidationType.Schema;
            settings.Schemas.Add(TypeMappingSchema);

            TypeMapping mapping;

            using (FileStream fs = File.OpenRead(fileName))
            {
                using (XmlReader reader = XmlReader.Create(fs, settings))
                {
                    XPathDocument doc = new XPathDocument(reader);
                    XPathNavigator nav = doc.CreateNavigator();

                    nav.MoveToFirstChild();
                    mapping = TypeMapping.LoadFromXml(nav);

                    reader.Close();
                }

                fs.Close();
            }

            return mapping;
        }

        private static TypeMapping LoadFromXml(XPathNavigator navigator)
        {
            TypeMapping tm = new TypeMapping();

            string uri = String.Empty;

            tm._source = navigator.GetAttribute("source", uri);
            tm._target = navigator.GetAttribute("target", uri);
            tm._defaultCodeType = navigator.GetAttribute("defaultCodeType", uri);
            tm._customAttribute = navigator.GetAttribute("customAttribute", uri);

            XPathNodeIterator ni = navigator.Select("map");

            while (ni.MoveNext())
            {
                XPathNavigator mapNav = ni.Current;

                string sqlType = mapNav.GetAttribute("sqlType", uri);
                string codeType = mapNav.GetAttribute("codeType", uri);
                string nullableCodeType = mapNav.GetAttribute("nullableCodeType", uri);

                tm._maps.Add(sqlType, codeType);

                if (!String.IsNullOrEmpty(nullableCodeType))
                    tm._nullableMaps.Add(sqlType, nullableCodeType);
            }

            return tm;
        }

        #endregion
    }
}
